/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.utils;

import cn.ac.nercis.pes.common.constant.common.PathConstants;
import cn.ac.nercis.pes.common.constant.project.SecurityLevel;
import lombok.NonNull;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;

/**
 * 文件管理工具类
 * @author zpy
 * @version 1.0.0
 */
public final class FileManage {
    private final static String FILE_RENAME = " - 副本";
    private final static String FILE_RENAME_NUMBER_FORMAT = " (%d)";
    private final static String EXPORT_TEMPLATE_FILE = "level_%s_asset_template.xlsx";

    private static String workspace;

    private FileManage(){}

    public static void initWorkspace(String path){
        workspace = path;
    }

    public static String getWorkspace(){
        return workspace;
    }

    public static String getPlugDir() {
        return Paths.get(getWorkspace(), PathConstants.PLUGS_DIR).toString();
    }

    public static String getAssetTemplateFile(SecurityLevel level) {
        if (level == SecurityLevel.FOUR) {
            level = SecurityLevel.THREE;
        }
        return Paths.get(getWorkspace(), PathConstants.ROOT_DIR, PathConstants.TEMPLATE_DIR, String.format(EXPORT_TEMPLATE_FILE, level.getLevel())).toString();
    }

    public static String getSystemDir(String systemId) {
        return Paths.get(getWorkspace(), PathConstants.ROOT_DIR, PathConstants.SYSTEM_DIR, systemId).toString();
    }

    public static String getBusinessContentDir(String systemId) {
        return Paths.get(getSystemDir(systemId), PathConstants.BUSINESS_CONTENT_DIR).toString();
    }

    public static String getNetworkTopologyDir(String systemId) {
        return Paths.get(getSystemDir(systemId), PathConstants.NETWORK_TOPOLOGY_DIR).toString();
    }

    public static String getCheckPointDir(String systemId){
        return Paths.get(getSystemDir(systemId),PathConstants.CHECK_POINT_DIR).toString();
    }

    public static String getPhotoFileBaseDir(String systemId){
        return Paths.get(getSystemDir(systemId),PathConstants.PHOTO_FILE_DIR).toString();
    }

    public static String getPhotoFileDir(String systemId,String layerTargetName){
        return Paths.get(getPhotoFileBaseDir(systemId),layerTargetName).toString();
    }

    public static String getProofBaseDir(String systemId) {
        return Paths.get(getSystemDir(systemId), PathConstants.PROOF_DIR).toString();
    }

    public static String getDelegateDir(String systemId) {
        return Paths.get(getProofBaseDir(systemId), PathConstants.DELEGATE_DIR).toString();
    }

    public static String getActivityDir(String systemId) {
        return Paths.get(getProofBaseDir(systemId), PathConstants.ACTIVITY_DIR).toString();
    }

    public static String getQualityDir(String systemId) {
        return Paths.get(getProofBaseDir(systemId), PathConstants.QUALITY_DIR).toString();
    }

    public static String getGradingDir(String systemId) {
        return Paths.get(getProofBaseDir(systemId), PathConstants.GRADING_DIR).toString();
    }

    public static String getProveDir(String systemId) {
        return Paths.get(getProofBaseDir(systemId), PathConstants.PROVE_FILE).toString();
    }

    public static List<File> findProofFiles(String systemId) {
        File baseDirFile = FileUtils.getFile(getProofBaseDir(systemId));
        try {
            return new ArrayList<>(FileUtils.listFiles(baseDirFile, null, true));
        } catch (Exception ignore) {
            return Collections.emptyList();
        }
    }

    public static List<File> findPhotoFiles(String systemId) {
        File baseDirFile = FileUtils.getFile(getPhotoFileBaseDir(systemId));
        try {
            return new ArrayList<>(FileUtils.listFiles(baseDirFile, null, true));
        } catch (Exception ignore) {
            return Collections.emptyList();
        }
    }

    public static List<File> findBusinessFiles(String systemId) {
        File baseDirFile = FileUtils.getFile(FileManage.getBusinessContentDir(systemId));
        try {
            return new ArrayList<>(FileUtils.listFiles(baseDirFile, null, true));
        } catch (Exception ignore) {
            return Collections.emptyList();
        }
    }

    public static FileFilter getPhotoFileFilter() {
        return file -> getImageExtensions()
                .stream()
                .anyMatch(extend -> StringUtils.endsWith(file.getName(), extend));
    }

    public static List<String> getImageExtensions(){
        return Arrays.asList(".png",
                ".jpg",".jpeg",".jpe",".jfif",
                ".gif",".dib",".bmp",
                ".tif",".tiff");
    }

    public static void copyFile(@NonNull File srcFile, @NonNull File destFile) throws IOException {
        if (!destFile.getParentFile().exists()) {
            FileUtils.createParentDirectories(destFile);
        }
        FileUtils.copyFile(srcFile, destFile);
    }

    public static void copyFile(@NonNull File destFile, @NonNull byte[] data) throws IOException {
        if (!destFile.getParentFile().exists()) {
            FileUtils.createParentDirectories(destFile);
        }
        FileUtils.writeByteArrayToFile(destFile, data);
    }

    public static void createDirectory(@NonNull File dirFile) throws IOException{
        if(!dirFile.exists()){
            FileUtils.forceMkdir(dirFile);
        }
    }

    public static List<File> listFiles(File sourceDir) {
        if (!sourceDir.exists()) {
            return Collections.emptyList();
        }
        File[] files = sourceDir.listFiles();
        return Optional.ofNullable(files)
                .map(Arrays::asList)
                .orElse(Collections.emptyList());
    }

    public static boolean isImageFile(String filePath){
        if(StringUtils.isBlank(filePath)){
            return false;
        }
        return getImageExtensions()
                .stream()
                .anyMatch(ext->StringUtils.endsWithIgnoreCase(filePath,ext));
    }

    public static Boolean existFileName(String fileName,List<String> fileNames){
        return fileNames.stream().anyMatch(name->StringUtils.equals(name,fileName));
    }

    public static String getFileRename(String fileName,List<String> fileNames){
        if(!existFileName(fileName,fileNames)){
            return fileName;
        }
        String fileNameWithoutSuffix = getFileNameWithoutSuffix(fileName);
        String suffix = getFileSuffix(fileName);
        String rename = fileNameWithoutSuffix.concat(FILE_RENAME);
        int startNumber = 2;
        while (existFileName(rename.concat(suffix),fileNames)){
            rename = fileNameWithoutSuffix.concat(FILE_RENAME)
                    .concat(String.format(FILE_RENAME_NUMBER_FORMAT,startNumber));
            startNumber++;
        }
        return rename.concat(suffix);
    }

    public static String getFileNameWithoutSuffix(String fileName){
        if(StringUtils.isBlank(fileName) || fileName.lastIndexOf(".") < 1){
            return fileName;
        }
        return fileName.substring(0,fileName.lastIndexOf("."));
    }


    public static String getFileSuffix(String fileName){
        if(StringUtils.isBlank(fileName) || fileName.lastIndexOf(".") < 1){
            return fileName;
        }
        return fileName.substring(fileName.lastIndexOf("."));
    }

    public static Boolean deleteFile(File file){
        try{
            FileUtils.delete(file);
            return true;
        }catch (IOException ex){
            return false;
        }
    }

    public static File createTempFile(String fileName,String suffix) throws IOException{
        return File.createTempFile(fileName,suffix);
    }

}
